package com.bifang.core.oplog.aspect;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.bifang.common.constant.enums.common.AuTypeEnum;
import com.bifang.common.constant.enums.common.AuthStatusEnum;
import com.bifang.common.constant.enums.common.BoolEnum;
import com.bifang.common.constant.enums.common.CommentTypeEnum;
import com.bifang.common.exception.AppException;
import com.bifang.common.util.CommonSecureUtil;
import com.bifang.common.util.IdWorkerUtil;
import com.bifang.common.util.OplogUtil;
import com.bifang.common.util.SessionUtil;
import com.bifang.common.vo.BaseAuditVO;
import com.bifang.common.vo.BasePageVO;
import com.bifang.common.vo.BaseVO;
import com.bifang.common.vo.OplogVO;
import com.bifang.common.annotations.OpApi;
import com.bifang.common.annotations.SaveOplog;
import com.bifang.core.dao.model.Oplog;
import com.bifang.core.dao.model.OplogFunction;
import com.bifang.core.dao.model.OplogHistory;
import com.bifang.core.dao.service.OplogFunctionService;
import com.bifang.core.dao.service.OplogHistoryService;
import com.bifang.core.dao.service.OplogService;
import com.bifang.core.oplog.integration.OplogIntegration;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

/***
 *日志处理切面
 * chenzh
 * 2020-01-15
 * */
@Aspect
@Component
@ConditionalOnExpression("${system.config.saveOplog}")
@Order(1)
public class OplogAspect {
    private static final Logger logger = LoggerFactory.getLogger(OplogAspect.class);

    @Autowired OplogIntegration oplogIntegration;
    @Autowired OplogService oplogService;
    @Autowired OplogHistoryService oplogHistoryService;
    @Autowired OplogFunctionService oplogFunctionService;

    @Value("${system.config.oplog.history.flag}")
    private Boolean oplogHistoryFlag;

    @Value("${system.config.user.encryption.flag}")
    private Boolean encryptionFlag;

    @Around(
            "(execution(* com.bifang..*.integration..*.*(..))||execution(* com.jwsoft..*.integration..*.*(..)))&&@annotation(saveOplog)")
    public Object aroundOplog(ProceedingJoinPoint joinPoint, SaveOplog saveOplog) throws Throwable {
        logger.info(
                "=========================================用户业务操作日志开始执行......=========================================");
        // 业务类型
        String operationType = saveOplog.operationType();
        // 业务名称
        String operationName = saveOplog.operationName();
        // 数据类型id使用字段
        String dataField = saveOplog.dataType();

        Object[] args = joinPoint.getArgs();
        OplogVO oplogVO = new OplogVO();
        oplogVO.setOperationType(operationType);
        oplogVO.setOperationName(operationName);
        oplogVO.setAuthStatus(AuthStatusEnum.NODO.getType());
        oplogVO.setLastFlag(BoolEnum.TRUE.getType());
        oplogVO.setAuType(saveOplog.auType().getType());
        oplogVO.setBatchFlag(BoolEnum.FALSE.getType());
        if ("batch".equals(dataField)) {
            oplogVO.setBatchFlag(BoolEnum.TRUE.getType());
            oplogVO.setFormKey("batchAuditRe");
        }
        oplogVO.setDataType(dataField);
        // 业务流水号
        oplogVO.setAutomaticFlag(BoolEnum.FALSE.getType());

        // 操作时间
        oplogVO.setOpTime(new Date());
        String date = DatePattern.PURE_DATE_FORMAT.format(new Date());
        oplogVO.setOpDate(Integer.parseInt(date));
        // 业务期 默认用系统时间
        int dateym = Integer.parseInt(date.substring(0, 6));
        oplogVO.setDateYm(dateym);
        if (args != null && args.length > 0) {
            Object argument = args[0];
            if (!(argument instanceof BaseVO)
                    && !(argument instanceof BasePageVO)
                    && !(argument instanceof BaseAuditVO)) {
                throw new AppException("业务日志保存传入参数必须继承BaseVO或者BasePageVO或者BaseAuditVO");
            }
            if (argument instanceof BaseVO) {
                BaseVO baseVO = (BaseVO) argument;
                oplogVO.setAccessToken(baseVO.getAccessToken());
                oplogVO.setReqIp(baseVO.getReqIp());
                oplogVO.setRouterId(baseVO.getOpRouterId());
                oplogVO.setUnionOplogId(baseVO.getOpOplogId());
                oplogVO.setFuncId(baseVO.getOpFuncId());
                if (baseVO.getBusNo() == null) {
                    oplogVO.setBusNo(new BigDecimal(IdWorkerUtil.getId()));
                    oplogVO.setOrderNo(1);

                } else {
                    oplogVO.setBusNo(baseVO.getBusNo());
                }
            } else if (argument instanceof BasePageVO) {
                BasePageVO basePageVO = (BasePageVO) argument;
                oplogVO.setAccessToken(basePageVO.getAccessToken());
                oplogVO.setReqIp(basePageVO.getReqIp());
                oplogVO.setRouterId(basePageVO.getOpRouterId());
                oplogVO.setUnionOplogId(basePageVO.getOpOplogId());
                oplogVO.setFuncId(basePageVO.getOpFuncId());
                if (basePageVO.getBusNo() == null) {
                    oplogVO.setBusNo(new BigDecimal(IdWorkerUtil.getId()));
                    oplogVO.setOrderNo(1);
                } else {
                    oplogVO.setBusNo(basePageVO.getBusNo());
                }
            } else if (argument instanceof BaseAuditVO) {
                BaseAuditVO baseAuditVO = (BaseAuditVO) argument;
                oplogVO.setAccessToken(baseAuditVO.getAccessToken());
                oplogVO.setReqIp(baseAuditVO.getReqIp());
                oplogVO.setRouterId(baseAuditVO.getOpRouterId());
                oplogVO.setUnionOplogId(baseAuditVO.getOpOplogId());
                oplogVO.setFuncId(baseAuditVO.getOpFuncId());
                oplogVO.setParam1(baseAuditVO.getBackToOplogId());
                oplogVO.setOpUserId(baseAuditVO.getAuthUserId());
                if (StringUtils.isNotBlank(baseAuditVO.getAutomaticFlag())) {
                    oplogVO.setAutomaticFlag(baseAuditVO.getAutomaticFlag());
                }
                if (StringUtils.isNotBlank(baseAuditVO.getCommentType())) {
                    oplogVO.setCommentType(baseAuditVO.getCommentType());
                }
                if (!AuTypeEnum.START.getType().equals(saveOplog.auType().getType())) {
                    BigDecimal busNo = baseAuditVO.getBusNo();
                    if (busNo != null) {
                        oplogVO.setBusNo(busNo);
                        QueryWrapper<Oplog> queryWrapper = new QueryWrapper<>();
                        queryWrapper
                                .lambda()
                                .eq(Oplog::getRbStatus, BoolEnum.FALSE.getType())
                                .eq(Oplog::getLastFlag, BoolEnum.TRUE.getType())
                                .eq(Oplog::getBusNo, busNo)
                                .eq(Oplog::getStatus, BoolEnum.TRUE.getType());
                        Oplog oldOplog = oplogService.getOne(queryWrapper);
                        if (oldOplog == null) {
                            oplogVO.setOrderNo(1);
                        } else {
                            int orderNo =
                                    oldOplog.getOrderNo() == null ? 1 : oldOplog.getOrderNo() + 1;
                            oplogVO.setOrderNo(orderNo);
                            oplogVO.setDataType(oldOplog.getDataType());
                            oplogVO.setOperationType(oldOplog.getOperationType());
                            oplogVO.setOperationName(oldOplog.getOperationName());
                            oplogVO.setDataId(oldOplog.getDataId());
                            oplogVO.setOrgId(oldOplog.getOrgId());
                            oplogVO.setOrgCode(oldOplog.getOrgCode());
                            oplogVO.setPersonId(oldOplog.getPersonId());
                            oplogVO.setParentId(oldOplog.getOplogId());
                            oplogVO.setRemarks(oldOplog.getRemarks());
                            UpdateWrapper<Oplog> oplogUpdateWrapper = new UpdateWrapper<>();
                            oplogUpdateWrapper
                                    .lambda()
                                    .set(Oplog::getLastFlag, BoolEnum.FALSE.getType())
                                    .eq(Oplog::getOplogId, oldOplog.getOplogId());
                            oplogService.update(oplogUpdateWrapper);
                            if (oplogHistoryFlag) {
                                UpdateWrapper<OplogHistory> oplogUpdateHiWrapper =
                                        new UpdateWrapper<>();
                                oplogUpdateHiWrapper
                                        .lambda()
                                        .set(OplogHistory::getLastFlag, BoolEnum.FALSE.getType())
                                        .eq(OplogHistory::getOplogId, oldOplog.getOplogId());
                                oplogHistoryService.update(oplogUpdateHiWrapper);
                            }
                        }
                    } else {
                        if (AuTypeEnum.OTHER.getType().equals(saveOplog.auType().getType())) {
                            oplogVO.setBusNo(new BigDecimal(IdWorkerUtil.getId()));
                            oplogVO.setOrderNo(1);
                        }
                    }
                    if (StringUtils.isNotBlank(baseAuditVO.getAuType())) {
                        oplogVO.setAuType(baseAuditVO.getAuType());
                    }
                    oplogVO.setAssignee(baseAuditVO.getCurAssigneeId());
                    oplogVO.setAssigneeType(baseAuditVO.getCurAssigneeType());
                    oplogVO.setAuthStatus(baseAuditVO.getAuthStatus());
                    oplogVO.setAuthRemarks(baseAuditVO.getAuthRemarks());
                    if (baseAuditVO.getAuthTime() == null) {
                        oplogVO.setAuthTime(new Date());
                    } else {
                        oplogVO.setAuthTime(baseAuditVO.getAuthTime());
                    }
                    oplogVO.setAuthUserId(baseAuditVO.getAuthUserId());
                    oplogVO.setActId(baseAuditVO.getActId());
                    oplogVO.setActName(baseAuditVO.getActName());
                    oplogVO.setProcDefId(baseAuditVO.getProcDefId());
                    oplogVO.setExecutionId(baseAuditVO.getExecutionId());
                    oplogVO.setFlowNodeId(baseAuditVO.getFlowNodeId());
                    if (StringUtils.isNotBlank(baseAuditVO.getFormKey())) {
                        oplogVO.setFormKey(baseAuditVO.getFormKey());
                    }
                    oplogVO.setTaskId(baseAuditVO.getTaskId());
                    oplogVO.setProcInstId(baseAuditVO.getProcInstId());
                    if (encryptionFlag) {
                        oplogVO.setApplicantId(
                                CommonSecureUtil.aesEncrypt(baseAuditVO.getApplicantId()));
                        oplogVO.setApplicantName(
                                CommonSecureUtil.aesEncrypt(baseAuditVO.getApplicantName()));
                    } else {
                        oplogVO.setApplicantId(baseAuditVO.getApplicantId());
                        oplogVO.setApplicantName(baseAuditVO.getApplicantName());
                    }
                    oplogVO.setApplicantType(baseAuditVO.getApplicantType());
                    oplogVO.setAssigneeType(baseAuditVO.getCurAssigneeType());
                    oplogVO.setAssignee(baseAuditVO.getCurAssigneeId());
                    oplogVO.setParam1(baseAuditVO.getBackToOplogId());

                    if (StringUtils.isNotBlank(baseAuditVO.getAuthUserId())) {
                        oplogVO.setAuthUserId(baseAuditVO.getAuthUserId());
                    }

                    if (baseAuditVO.getAuthTime() == null) {
                        oplogVO.setAuthTime(new Date());
                    } else {
                        oplogVO.setAuthTime(baseAuditVO.getAuthTime());
                    }
                }
                if (AuTypeEnum.START.getType().equals(saveOplog.auType().getType())) {
                    if (oplogVO.getBusNo() == null) {
                        // 启动节点 生成业务流水号
                        oplogVO.setBusNo(new BigDecimal(IdWorkerUtil.getId()));
                        oplogVO.setOrderNo(1);
                        oplogVO.setCommentType(CommentTypeEnum.INIT.toString());
                    } else {
                        // 重新到启动节点
                        QueryWrapper<Oplog> queryWrapper = new QueryWrapper<>();
                        queryWrapper
                                .lambda()
                                .eq(Oplog::getRbStatus, BoolEnum.FALSE.getType())
                                .eq(Oplog::getLastFlag, BoolEnum.TRUE.getType())
                                .eq(Oplog::getBusNo, oplogVO.getBusNo())
                                .eq(Oplog::getStatus, BoolEnum.TRUE.getType());
                        Oplog oldOplog = oplogService.getOne(queryWrapper);
                        if (oldOplog == null) {
                            throw new AppException("数据异常,重新提交业务未找到之前日志");
                        } else {
                            int orderNo =
                                    oldOplog.getOrderNo() == null ? 1 : oldOplog.getOrderNo() + 1;
                            oplogVO.setOrderNo(orderNo);
                            oplogVO.setDataType(oldOplog.getDataType());
                            oplogVO.setDataId(oldOplog.getDataId());
                            oplogVO.setOrgId(oldOplog.getOrgId());
                            oplogVO.setOrgCode(oldOplog.getOrgCode());
                            oplogVO.setPersonId(oldOplog.getPersonId());
                            oplogVO.setParentId(oldOplog.getOplogId());
                            oplogVO.setRemarks(oldOplog.getRemarks());
                            UpdateWrapper<Oplog> oplogUpdateWrapper = new UpdateWrapper<>();
                            oplogUpdateWrapper
                                    .lambda()
                                    .set(Oplog::getLastFlag, BoolEnum.FALSE.getType())
                                    .eq(Oplog::getOplogId, oldOplog.getOplogId());
                            oplogService.update(oplogUpdateWrapper);
                            if (oplogHistoryFlag) {
                                UpdateWrapper<OplogHistory> oplogUpdateHiWrapper =
                                        new UpdateWrapper<>();
                                oplogUpdateHiWrapper
                                        .lambda()
                                        .set(OplogHistory::getLastFlag, BoolEnum.FALSE.getType())
                                        .eq(OplogHistory::getOplogId, oldOplog.getOplogId());
                                oplogHistoryService.update(oplogUpdateHiWrapper);
                            }
                        }
                        if (StringUtils.isBlank(oplogVO.getCommentType())) {
                            oplogVO.setCommentType(CommentTypeEnum.CXTJ.toString());
                        }
                    }
                }
            } else {
                throw new AppException("业务日志保存传入第一个参数必须继承BaseVO或者BasePageVO或者BaseAuditVO");
            }

            Long oplogId =
                    oplogIntegration.saveOpLog(
                            oplogVO, argument, saveOplog.auType().getType(), saveOplog.dataType());
            logger.info("操作日志id：" + oplogId);

            Object ret = joinPoint.proceed();
            boolean flag = false;
            Oplog oplog = oplogService.getById(oplogId);
            Object[] argsNew = joinPoint.getArgs();
            if (argsNew != null && argsNew.length > 0) {
                Object argumentNew = argsNew[0];
                BeanWrapper beanWrapper = new BeanWrapperImpl(argumentNew);
                if (argumentNew instanceof BaseAuditVO) {
                    BaseAuditVO baseAuditVO = (BaseAuditVO) argument;
                    if (StringUtils.isBlank(oplog.getActId())) {
                        oplog.setActId(baseAuditVO.getActId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getActName())) {
                        oplog.setActName(baseAuditVO.getActName());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getExecutionId())) {
                        oplog.setExecutionId(baseAuditVO.getExecutionId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getProcDefId())) {
                        oplog.setProcDefId(baseAuditVO.getProcDefId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getCommentType())) {
                        oplog.setCommentType(baseAuditVO.getCommentType());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getAssigneeType())) {
                        oplog.setAssigneeType(baseAuditVO.getCurAssigneeType());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getAssignee())) {
                        oplog.setAssignee(baseAuditVO.getCurAssigneeId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getAuthStatus())
                            || AuthStatusEnum.NODO.getType().equals(oplog.getAuthStatus())) {
                        if (StringUtils.isNotBlank(baseAuditVO.getAuthStatus())) {
                            oplog.setAuthStatus(baseAuditVO.getAuthStatus());
                            flag = true;
                        }
                    }
                    if (StringUtils.isBlank(oplog.getAuthRemarks())) {
                        oplog.setAuthRemarks(baseAuditVO.getAuthRemarks());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getTaskId())) {
                        oplog.setTaskId(baseAuditVO.getTaskId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getFormKey())) {
                        oplog.setFormKey(baseAuditVO.getFormKey());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getProcInstId())) {
                        oplog.setProcInstId(baseAuditVO.getProcInstId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getParam1())) {
                        oplog.setParam1(baseAuditVO.getBackToOplogId());
                        flag = true;
                    }
                    if (StringUtils.isBlank(oplog.getAuthUserId())) {
                        if (StringUtils.isNotBlank(baseAuditVO.getAuthUserId())) {
                            oplog.setAuthUserId(baseAuditVO.getAuthUserId());
                        } else {
                            String authUserId = SessionUtil.getUserId();
                            if (StringUtils.isBlank(authUserId)) {
                                oplog.setAuthUserId("robot");
                            } else {
                                oplog.setAuthUserId(authUserId);
                            }
                        }
                        flag = true;
                    }
                    if (oplog.getAuthTime() == null) {
                        if (baseAuditVO.getAuthTime() == null) {
                            oplog.setAuthTime(new Date());
                        } else {
                            oplog.setAuthTime(baseAuditVO.getAuthTime());
                        }
                        flag = true;
                    }
                    if (oplog.getApplicantType() == null) {
                        if (!StringUtils.isEmpty(baseAuditVO.getApplicantType())) {
                            oplog.setApplicantType(baseAuditVO.getApplicantType());
                            flag = true;
                        }
                    }
                    if (oplog.getApplicantId() == null) {
                        if (!StringUtils.isEmpty(baseAuditVO.getApplicantId())) {
                            oplog.setApplicantId(baseAuditVO.getApplicantId());
                            flag = true;
                        }
                    }
                    if (oplog.getApplicantName() == null) {
                        if (!StringUtils.isEmpty(baseAuditVO.getApplicantName())) {
                            oplog.setApplicantName(baseAuditVO.getApplicantName());
                            flag = true;
                        }
                    }
                }

                if (StringUtils.isBlank(oplog.getFuncId())) {
                    if (beanWrapper.isWritableProperty("opFuncId")) {
                        if (beanWrapper.getPropertyValue("opFuncId") != null) {
                            oplog.setFuncId(beanWrapper.getPropertyValue("opFuncId").toString());
                            flag = true;
                        }
                    }
                }
                // 数据类型id使用字段
                if (!"other".equals(dataField) && !"batch".equals(dataField)) {
                    if ((StringUtils.isBlank(oplog.getDataId()) || "0".equals(oplog.getDataId()))
                            && StringUtils.isNotBlank(dataField)) {
                        if (beanWrapper.isWritableProperty(dataField)) {
                            if (beanWrapper.getPropertyValue(dataField) != null) {
                                oplog.setDataId(beanWrapper.getPropertyValue(dataField).toString());
                                flag = true;
                            }
                        }
                    }
                }
                if (AuTypeEnum.START.getType().equals(saveOplog.auType().getType())) {
                    if (!BoolEnum.TRUE.getType().equals(oplog.getAuditFlag())) {
                        if (StringUtils.isNotBlank(oplog.getFuncId())) {
                            OplogFunction oplogFunction =
                                    oplogFunctionService.getById(oplog.getFuncId());
                            if (!ObjectUtils.isEmpty(oplogFunction)) {
                                // 判断接口中是否有audit 审核方法，如果有该方法则直接调用
                                Class clzz = joinPoint.getTarget().getClass();
                                // 获取扫描类下所有方法
                                Method[] methods = ReflectionUtils.getAllDeclaredMethods(clzz);
                                for (Method method : methods) {
                                    // 找到带有OpenApi 注解的方法
                                    SaveOplog audit =
                                            AnnotationUtils.findAnnotation(method, SaveOplog.class);
                                    if (null == audit) {
                                        continue;
                                    }
                                    if (StringUtils.isNotBlank(oplogFunction.getNextFuncCode())) {
                                        OpApi opApi =
                                                AnnotationUtils.findAnnotation(method, OpApi.class);
                                        if (null == opApi) {
                                            continue;
                                        }
                                        if (!oplogFunction
                                                .getNextFuncCode()
                                                .equals(opApi.funcCode())) {
                                            continue;
                                        }
                                    }
                                    if (AuTypeEnum.AUDIT
                                            .getType()
                                            .equals(audit.auType().getType())) {
                                        try {
                                            Object obj = args[0];
                                            if (obj instanceof BaseAuditVO) {
                                                BaseAuditVO baseAuditVO = (BaseAuditVO) obj;
                                                baseAuditVO.setAuthStatus(
                                                        AuthStatusEnum.YES.getType());
                                                baseAuditVO.setAuthRemarks("自动审核通过");
                                                baseAuditVO.setAuthUserId(
                                                        SessionUtil.getUserId() == null
                                                                ? "robot"
                                                                : SessionUtil.getUserId());
                                                baseAuditVO.setAuthTime(new Date());
                                                baseAuditVO.setAuType(AuTypeEnum.END.getType());
                                                baseAuditVO.setAutomaticFlag(
                                                        BoolEnum.TRUE.getType());
                                                baseAuditVO.setCommentType(
                                                        CommentTypeEnum.SP.toString());
                                            }
                                            method.invoke(joinPoint.getTarget(), obj);
                                        } catch (IllegalAccessException e) {
                                            logger.error("调用审核异常", e);
                                            throw new AppException("调用自动审核异常");
                                        } catch (InvocationTargetException e) {
                                            logger.error("调用审核异常", e);
                                            throw new AppException("调用自动审核异常");
                                        }
                                    }
                                }
                            }
                        }
                        oplog.setAuthStatus(AuthStatusEnum.YES.getType());
                        oplog.setAuthRemarks("自动审核通过");
                        oplog.setAuthUserId(
                                SessionUtil.getUserId() == null
                                        ? "robot"
                                        : SessionUtil.getUserId());
                        oplog.setAuthTime(new Date());
                        oplog.setAutomaticFlag(BoolEnum.TRUE.getType());
                        flag = true;
                    }
                }

                if (flag) {
                    oplogService.updateById(oplog);
                    if (oplogHistoryFlag) {
                        if (oplogHistoryFlag == null) {
                            oplogHistoryFlag = false;
                        }
                        if (oplogHistoryFlag) {
                            OplogHistory oplogHistory = Convert.convert(OplogHistory.class, oplog);
                            oplogHistoryService.updateById(oplogHistory);
                        }
                    }
                }
            }
            logger.info(
                    "=========================================用户操作日志结束执行......=========================================");
            OplogUtil.del(null);
            return ret;
        } else {
            throw new AppException("操作日志相关方法入参必须传入继承BaseVO或者BasePageVO或者BaseAuditVO的请求实体类");
        }
    }
}
